package com.stephen.bp.service;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.stephen.bp.mapper.ScheduleMapper;
import com.stephen.bp.mapper.TeamMapper;
import com.stephen.bp.mapper.UserMapper;
import com.stephen.bp.model.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author qiuwenwei
 */
@Log4j2
@Service
public class RoomService {
    public static final HashMap<String, Room> roomHashMap = new HashMap<>();
    @Autowired
    RecordService recordService;
    @Autowired
    TeamMapper teamMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    ScheduleMapper scheduleMapper;
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    private static final int TIME = 60;
    private static final int FINAL_TIME = 3;

    public String getTime(String roomId) {
        Room room = roomHashMap.get(roomId);
        long time = room.getTimeout() - System.currentTimeMillis() / 1000;
        time = time <= 0 ? 0 : time;
        return String.valueOf(time);
    }

    public void selectRole(String username, String roomId, String content) {
        Room room = roomHashMap.get(roomId);
        chooseRole(roomId, username, content);
        for (User user : room.getUsers()) {
            RequestAndResponse requestAndResponse = new RequestAndResponse();
            requestAndResponse.setAction(Action.INTO);
            requestAndResponse.setContent(JSONObject.toJSONString(room));
            UserChannel.writeAndFlush0(user.getUsername(), requestAndResponse);
        }
    }

    public void joinRoom(String username, String roomId) {
        Room room = roomHashMap.get(roomId);
        //房间是否满员
        if (room.getUsers()[1] != null) {
            //发送房间信息
            RequestAndResponse requestAndResponse = new RequestAndResponse();
            requestAndResponse.setRoomId(roomId);
            requestAndResponse.setAction(Action.JOIN_ROOM);
            requestAndResponse.setContent(JSONObject.toJSONString(room));
            UserChannel.writeAndFlush0(username, requestAndResponse);
            return;
        } else {
            //如果没满员，第一个加入的肯定是创建房间的，也已经加入了，所以判断自己是不是第一个
            if (!room.getUsers()[0].getUsername().equals(username)) {
                //如果自己不是第一个，说明房间就等你加入了
                room.getUsers()[1] = getUser(username);
                //所有人加入之后选择先后
                chooseFirst(roomId);
            } else {
                //自己不要重复加入房间
                //发送房间信息
                RequestAndResponse requestAndResponse = new RequestAndResponse();
                requestAndResponse.setRoomId(roomId);
                requestAndResponse.setAction(Action.CREATE_ROOM);
                requestAndResponse.setContent(JSONObject.toJSONString(room));
                UserChannel.writeAndFlush0(username, requestAndResponse);
                return;
            }
        }
        //所有人都加入了房间
        for (User user : room.getUsers()) {
            RequestAndResponse requestAndResponse = new RequestAndResponse();
            requestAndResponse.setRoomId(roomId);
            requestAndResponse.setAction(Action.JOIN_ROOM);
            requestAndResponse.setContent(JSONObject.toJSONString(room));
            UserChannel.writeAndFlush0(user.getUsername(), requestAndResponse);
        }
    }

    public void createRoom(String username, String roomId) {
        LambdaQueryWrapper<Team> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(Team::getOrderNum);
        Room room = new Room(roomId, (ArrayList<Team>) teamMapper.selectList(queryWrapper));
        User[] users = new User[2];
        users[0] = getUser(username);
        room.setUsers(users);
        roomHashMap.put(roomId, room);
    }

    private User getUser(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(User::getId, User::getLoginName, User::getUsername, User::getImage);
        queryWrapper.eq(User::getUsername, username);
        return userMapper.selectOne(queryWrapper);
    }

    private void chooseFirst(String roomId) {
        Room room = roomHashMap.get(roomId);
//        if ("TGL".equals(room.getUsers()[0].getUsername()) || "TGL".equals(room.getUsers()[1].getUsername())) {
//            room.getUsers()[0].setRole("TGL".equals(room.getUsers()[0].getUsername()) ? "F" : "S");
//            room.getUsers()[1].setRole("TGL".equals(room.getUsers()[1].getUsername()) ? "F" : "S");
//            return;
//        }
        if (System.currentTimeMillis() % 2 == 0) {
            room.getUsers()[0].setRole("F");
            room.getUsers()[1].setRole("S");
        } else {
            room.getUsers()[1].setRole("F");
            room.getUsers()[0].setRole("S");
        }
    }


    private void chooseRole(String roomId, String username, String role) {
        Room room = roomHashMap.get(roomId);
        User[] users = room.getUsers();
        if (users[0].getUsername().equals(username)) {
            users[0].setRole(role);
            users[1].setRole("A".equals(role) ? "B" : "A");
        } else {
            users[1].setRole(role);
            users[0].setRole("A".equals(role) ? "B" : "A");
        }
        if ("A".equals(users[0].getRole())) {
            room.setAUser(userMapper.selectById(users[0].getId()));
            room.setBUser(userMapper.selectById(users[1].getId()));
        } else {
            room.setAUser(userMapper.selectById(users[1].getId()));
            room.setBUser(userMapper.selectById(users[0].getId()));
        }
        room.getAUser().setPassword(null);
        room.getBUser().setPassword(null);
    }

    public synchronized void start(String username, String roomId) {
        Room room = roomHashMap.get(roomId);
        if (room == null) {
            log.error("房间号不存在{}", roomId);
            return;
        }
        if (!room.isFinish() && !room.isStart()) {
            room.setTimeout(System.currentTimeMillis() / 1000 + TIME);
            room.setStart(true);
            publish(roomId);
            updateSchedule(roomId, "进行中");
            new Thread(() -> check(roomId)).start();
        } else {
            publish(roomId, username);
        }
    }

    private void updateSchedule(String roomId, String status) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getRoomId, roomId);
        Schedule schedule = scheduleMapper.selectOne(queryWrapper);
        schedule.setStatus(status);
        schedule.setFinishTime(new Date());
        scheduleMapper.updateById(schedule);
    }

    private void finish(String roomId) {
        Room room = roomHashMap.get(roomId);
        room.setStart(false);
        room.setFinish(true);
        publishTime(roomId, "0");
        recordService.record(room);
        updateSchedule(roomId, "已结束");
    }

    private void check(String roomId) {
        while (true) {
            try {
                Room room = roomHashMap.get(roomId);
                if (room.getTimeout() + FINAL_TIME <= System.currentTimeMillis() / 1000) {
                    if (!room.isStart()) {
                        publishTime(roomId, "0");
                        return;
                    }
                    Action[] actions = room.getStageAction().get(room.getStage());
                    if (actions[0].equals(Action.FINISH_ONE)) {
                        room.setStageName("第二阶段");
                        room.setTimeout(System.currentTimeMillis() / 1000 + TIME);
                        room.setStage(room.getStage() + 1);
                        publish(roomId);
                    } else {
                        if (!actions[0].equals(Action.WAIT)) {
                            decision(room.getAUser().getUsername(), roomId, room.getSelectTeam("A").get(0).getName(), true);
                        }
                        if (!actions[1].equals(Action.WAIT)) {
                            decision(room.getBUser().getUsername(), roomId, room.getSelectTeam("B").get(0).getName(), true);
                        }
                    }
                }
                String time = getTime(roomId);
                publishTime(roomId, time);
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    Action getActionByStage(String roomId, String role) {
        Room room = roomHashMap.get(roomId);
        Action[] actions = room.getStageAction().get(room.getStage());
        return "A".equals(role) ? actions[0] : actions[1];
    }

    private Team getById(ArrayList<Team> teamArrayList, String name) {
        for (Team team : teamArrayList) {
            if (team.getName().equals(name)) {
                return team;
            }
        }
        return null;
    }

    private User getById(String roomId, String name) {
        Room room = roomHashMap.get(roomId);
        for (User user : room.getUsers()) {
            if (user.getUsername().equals(name)) {
                return user;
            }
        }
        return null;
    }


    private void select(String roomId, User user, Team team, boolean timeout) {
        Room room = roomHashMap.get(roomId);
        if ("第一阶段".equals(room.getStageName())) {
            if ("A".equals(user.getRole())) {
                room.getASelectTeam().add(team);
                if (timeout) {
                    room.getATimeoutSelectTeam().add(team.getName());
                }
            } else {
                room.getBSelectTeam().add(team);
                if (timeout) {
                    room.getBTimeoutSelectTeam().add(team.getName());
                }
            }
        } else {
            if ("A".equals(user.getRole())) {
                room.getAFinalSelectTeam().add(team);
                if (timeout) {
                    room.getATimeoutFinalSelectTeam().add(team.getName());
                }
            } else {
                room.getBFinalSelectTeam().add(team);
                if (timeout) {
                    room.getBTimeoutFinalSelectTeam().add(team.getName());
                }
            }
        }
    }

    private void ban(String roomId, User user, Team team, boolean timeout) {
        Room room = roomHashMap.get(roomId);
        if ("A".equals(user.getRole())) {
            room.getABanTeam().add(team);
            if (timeout) {
                room.getATimeoutBanTeam().add(team.getName());
            }
        } else {
            room.getBBanTeam().add(team);
            if (timeout) {
                room.getBTimeoutBanTeam().add(team.getName());
            }
        }
    }

    public synchronized void decision(String username, String roomId, String name, boolean timeout) {
        Room room = roomHashMap.get(roomId);
        Action[] actions = room.getStageAction().get(room.getStage());
        User user = getById(roomId, username);
        Team team;
        assert user != null;
        Action action = "A".equals(user.getRole()) ? actions[0] : actions[1];
        switch (action) {
            case SELECT:
                team = getById(room.getSelectTeam(user.getRole()), name);
                select(roomId, user, team, timeout);
                room.getSelectTeam(user.getRole()).remove(team);
                break;
            case BAN:
                team = getById(room.getSelectTeam(user.getRole()), name);
                ban(roomId, user, team, timeout);
                room.getSelectTeam(user.getRole()).remove(team);
                break;
            case FINISH_ONE:
                skip(roomId, user.getUsername());
                if (allSkip(roomId)) {
                    room.setStageName("第二阶段");
                    room.setStage(room.getStage() + 1);
                    room.setTimeout(System.currentTimeMillis() / 1000 + TIME);
                    publish(roomId);
                }
                return;
        }
        if ("第一阶段".equals(room.getStageName()) && room.getStage() >= 7) {
            room.getASelectTeam().forEach(e -> {
                Team t = new Team();
                t.setImage(e.getImage());
                t.setName(e.getName());
                room.getACanSelectTeam().add(t);
            });
            room.getBSelectTeam().forEach(e -> {
                Team t = new Team();
                t.setImage(e.getImage());
                t.setName(e.getName());
                room.getBCanSelectTeam().add(t);
            });
        }
        if ("第二阶段".equals(room.getStageName()) && room.getStage() >= room.getStageAction().size() - 2) {
            room.setStage(room.getStage() + 1);
            room.setTimeout(System.currentTimeMillis() / 1000);
            publish(roomId);
            finish(roomId);
            return;
        }
        room.setStage(room.getStage() + 1);
        room.setTimeout(System.currentTimeMillis() / 1000 + TIME);
        publish(roomId);
    }

    private void skip(String roomId, String username) {
        Room room = roomHashMap.get(roomId);
        if (room.getUsers()[0].getUsername().equals(username)) {
            room.getUsers()[0].setSkip(true);
        }
        if (room.getUsers()[1].getUsername().equals(username)) {
            room.getUsers()[1].setSkip(true);
        }
    }

    private boolean allSkip(String roomId) {
        Room room = roomHashMap.get(roomId);
        return room.getUsers()[0].isSkip() && room.getUsers()[1].isSkip();
    }

    private void publishTime(String roomId, String time) {
        Room room = roomHashMap.get(roomId);
        for (User user : room.getUsers()) {
            RequestAndResponse requestAndResponse = new RequestAndResponse();
            requestAndResponse.setAction(Action.TIME);
            requestAndResponse.setContent(time);
            UserChannel.writeAndFlush0(user.getUsername(), requestAndResponse);
        }
    }

    private void publish(String roomId) {
        publish(roomId, null);
    }

    private void publish(String roomId, String username) {
        Room room = roomHashMap.get(roomId);
        for (User user : room.getUsers()) {
            if (username != null && !user.getUsername().equals(username)) {
                continue;
            }
            RequestAndResponse requestAndResponse = new RequestAndResponse();
            requestAndResponse.setAction(getActionByStage(roomId, user.getRole()));
            if (requestAndResponse.getAction().equals(Action.WAIT)) {
                requestAndResponse.setExtra(getActionByStage(roomId, "A".equals(user.getRole()) ? "B" : "A"));
            }
            requestAndResponse.setContent(JSONObject.toJSONString(room));
            UserChannel.writeAndFlush0(user.getUsername(), requestAndResponse);
        }
    }

    public boolean isExist(String roomId) {
        return roomHashMap.containsKey(roomId);
    }

    public static String generateRoomNumber() {
        // 生成随机六位数字房间号
        StringBuilder roomNumber = new StringBuilder();
        for (int i = 0; i < 8; i++) {
            roomNumber.append(SECURE_RANDOM.nextInt(10)); // 生成 0 到 9 的随机数字
        }
        return roomNumber.toString();
    }

    private Schedule getWaitingSchedule(String username) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(wq -> wq.eq(Schedule::getUser1, username).or().eq(Schedule::getUser2, username));
        queryWrapper.eq(Schedule::getStatus, "待开始");
        List<Schedule> schedules = scheduleMapper.selectList(queryWrapper);
        return schedules.size() == 0 ? null : schedules.get(0);
    }

    public Schedule getRunningSchedule(String username) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(wq -> wq.eq(Schedule::getUser1, username).or().eq(Schedule::getUser2, username));
        queryWrapper.eq(Schedule::getStatus, "进行中");
        List<Schedule> schedules = scheduleMapper.selectList(queryWrapper);
        return schedules.size() == 0 ? null : schedules.get(0);
    }

    public synchronized void join(String username, RequestAndResponse requestAndResponse) {
        Schedule runningSchedule = getRunningSchedule(username);
        if (runningSchedule != null) {
            //如果还有进行中的房间，无法加入新房间
            requestAndResponse.setAction(Action.JOIN_ROOM_ERROR_RUNNING);
            UserChannel.writeAndFlush0(username, requestAndResponse);
            return;
        }
        Schedule waitingSchedule = getWaitingSchedule(username);
        if (waitingSchedule == null) {
            //如果没有待加入的房间
            requestAndResponse.setAction(Action.JOIN_ROOM_ERROR);
            UserChannel.writeAndFlush0(username, requestAndResponse);
            return;
        }
        if (isExist(waitingSchedule.getRoomId())) {
            //房间创建了
            joinRoom(username, waitingSchedule.getRoomId());
        } else {
            //房间还没被创建
            requestAndResponse.setAction(Action.CREATE_ROOM);
            requestAndResponse.setRoomId(waitingSchedule.getRoomId());
            createRoom(username, waitingSchedule.getRoomId());
            UserChannel.writeAndFlush0(username, requestAndResponse);
        }
    }
}
